
# 从qtpy库的QtWidgets模块导入所有组件
from qtpy.QtWidgets import *
# 从qtpy库导入QtCore和QtGui模块，其中QtGui后续未使用，可移除
from qtpy import QtCore, QtGui


class KeyboardModifiersCaptureWidget(QPushButton):
    """
    KeyboardModifiersCaptureWidget类继承自QPushButton，用于捕获键盘修饰键。
    支持用户点击按钮开始捕获，通过按下Enter键确认、Esc键清除操作。
    捕获到的修饰键信息会通过信号发射出去。

    :ivar captured: 自定义信号，当捕获到键盘修饰键时发射，携带捕获到的修饰键信息。
    """

    # 定义一个信号，当捕获到键盘修饰键时发射，参数类型为object
    captured = QtCore.Signal(object)

    def __init__(self, parent=None):
        """
        初始化KeyboardModifiersCaptureWidget实例。

        :param parent: 父控件，默认为None，用于指定该控件的父级窗口。
        """
        # 调用父类QPushButton的构造函数
        super(KeyboardModifiersCaptureWidget, self).__init__(parent)
        # 初始化当前的键盘修饰键为无修饰键，此处存在未解析特性引用问题
        self._currentModifiers = QtCore.Qt.NoModifier
        # 设置按钮的初始文本为 "NoModifier"
        self.setText("NoModifier")
        # 标记当前是否处于捕获修饰键的状态
        self.bCapturing = False
        # 设置按钮为可勾选状态，方便视觉反馈
        self.setCheckable(True)
        # 设置按钮的提示信息，告知用户操作方式
        self.setToolTip(
            "<b>Left click</b> to start capturing.<br><b>Enter</b> to accept.<br><b>Esc</b> to clear"
        )

        # 设置按钮的上下文菜单策略为ActionsContextMenu，此处存在未解析特性引用问题
        self.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
        # 创建一个名为 "Reset" 的动作，用于重置按钮状态
        self.actionReset = QAction("Reset", None)
        # 连接动作的触发信号到resetToDefault方法，点击该动作时触发重置操作
        self.actionReset.triggered.connect(self.resetToDefault)
        # 将动作添加到按钮的上下文菜单中
        self.addAction(self.actionReset)

    def resetToDefault(self):
        """
        将当前的键盘修饰键重置为无修饰键，并停止捕获操作，恢复按钮初始状态。
        """
        # 重置当前的键盘修饰键为无修饰键，此处存在未解析特性引用问题
        self.currentModifiers = QtCore.Qt.NoModifier
        # 停止捕获修饰键
        self.bCapturing = False
        # 取消按钮的勾选状态
        self.setChecked(False)

    @staticmethod
    def modifiersToString(modifiers):
        """
        将键盘修饰键信息转换为易读的字符串表示。

        :param modifiers: 键盘修饰键信息，通常是一个位掩码。
        :return: 包含修饰键名称的字符串，多个修饰键用 ' + ' 连接，若无修饰键则返回 "No Modifier"。
        """
        # 用于存储检测到的修饰键名称
        modifier_list = []
        # 检查是否按下Shift键，此处存在未解析特性引用问题
        if modifiers & QtCore.Qt.ShiftModifier:
            modifier_list.append("Shift")
        # 检查是否按下Control键，此处存在未解析特性引用问题
        if modifiers & QtCore.Qt.ControlModifier:
            modifier_list.append("Control")
        # 检查是否按下Alt键，此处存在未解析特性引用问题
        if modifiers & QtCore.Qt.AltModifier:
            modifier_list.append("Alt")
        # 检查是否按下Meta键，此处存在未解析特性引用问题
        if modifiers & QtCore.Qt.MetaModifier:
            modifier_list.append("Meta")
        # 如果列表中有元素，则用 ' + ' 连接成字符串，否则返回 "No Modifier"
        return " + ".join(modifier_list) if modifier_list else "No Modifier"

    def mousePressEvent(self, event):
        """
        处理鼠标按下事件，当左键点击且当前未处于捕获状态时，开始捕获键盘修饰键。

        :param event: 鼠标事件对象，包含鼠标点击的相关信息。
        """
        # 检查是否为鼠标左键点击
        if event.button() == QtCore.Qt.MouseButton.LeftButton:
            # 检查当前是否未处于捕获修饰键的状态
            if not self.bCapturing:
                # 开始捕获修饰键
                self.bCapturing = True
                # 调用父类的鼠标按下事件处理方法，确保默认行为正常执行
                super(KeyboardModifiersCaptureWidget, self).mousePressEvent(event)
                # 更新按钮文本，提示用户正在捕获修饰键
                self.setText("capturing...")

    @property
    def currentModifiers(self):
        """
        获取当前的键盘修饰键信息。

        :return: 当前的键盘修饰键信息，通常是一个位掩码。
        """
        return self._currentModifiers

    @currentModifiers.setter
    def currentModifiers(self, value):
        """
        设置当前的键盘修饰键信息，并更新按钮文本，发射捕获信号通知外部。

        :param value: 新的键盘修饰键信息，通常是一个位掩码。
        """
        # 更新当前的键盘修饰键信息
        self._currentModifiers = value
        # 根据新的修饰键信息更新按钮文本
        self.setText(self.modifiersToString(self._currentModifiers))
        # 发射捕获信号，将新的修饰键信息传递给外部的信号接收者
        self.captured.emit(self._currentModifiers)

    def keyPressEvent(self, event):
        """
        处理键盘按键事件，根据按下的按键（如Esc、Enter）执行相应操作。

        :param event: 键盘事件对象，包含按下的按键和修饰键等信息。
        """
        # 调用父类的键盘按键事件处理方法，确保默认行为正常执行
        super(KeyboardModifiersCaptureWidget, self).keyPressEvent(event)
        # 获取按下的按键代码
        key = event.key()
        # 检查是否按下Esc键，若按下则重置为默认状态，此处存在未解析特性引用问题
        if key == QtCore.Qt.Key_Escape:
            self.resetToDefault()
            # 停止捕获修饰键
            self.bCapturing = False
            # 取消按钮的勾选状态
            self.setChecked(False)
            return

        # 检查是否按下Enter键且当前处于捕获修饰键的状态，此处存在未解析特性引用问题
        if key == QtCore.Qt.Key_Return and self.bCapturing:
            # 停止捕获修饰键
            self.bCapturing = False
            # 取消按钮的勾选状态
            self.setChecked(False)
            # 更新按钮状态，触发重绘
            self.update()

        # 如果当前处于捕获修饰键的状态
        if self.bCapturing:
            # 更新当前的键盘修饰键信息为事件中的修饰键信息
            self.currentModifiers = event.modifiers()


if __name__ == "__main__":
    import sys

    # 创建一个QApplication实例，用于管理应用程序的资源和事件循环
    a = QApplication(sys.argv)

    # 创建KeyboardModifiersCaptureWidget实例
    w = KeyboardModifiersCaptureWidget()
    # 显示窗口
    w.show()

    # 进入应用程序的事件循环，等待用户操作，直到窗口关闭
    sys.exit(a.exec_())